﻿using System;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Engine
{
    public static class Input
    {
        static MouseState currentMouseState;
        static MouseState oldMouseState;
        static KeyboardState currentKeyboardState;
        static KeyboardState oldKeyboardState;
        static GamePadState []currentGamePadState;
        static GamePadState []oldGamePadState;

        static int mTimer = 0;
        static int mRelease = 1000;
        static int mDelay = 100;
        static int[,] mButtonHolder = new int[4, 4];

        #region LoadAndSaveData

        public static void LoadNewData()
        {
            currentMouseState = Mouse.GetState();
            currentKeyboardState = Keyboard.GetState();
            currentGamePadState = new GamePadState[4];
            currentGamePadState[0] = GamePad.GetState(PlayerIndex.One);
            currentGamePadState[1] = GamePad.GetState(PlayerIndex.Two);
            currentGamePadState[2] = GamePad.GetState(PlayerIndex.Three);
            currentGamePadState[3] = GamePad.GetState(PlayerIndex.Four);
        }
        public static void SaveOldData()
        {
            oldMouseState = currentMouseState;
            oldKeyboardState = currentKeyboardState;
            oldGamePadState = new GamePadState[4];
            oldGamePadState[0] = currentGamePadState[0];
            oldGamePadState[1] = currentGamePadState[1];
            oldGamePadState[2] = currentGamePadState[2];
            oldGamePadState[3] = currentGamePadState[3];
        }
        #endregion

        public static GamePadState GetGamePad(int index)
        {
            return currentGamePadState[index];
        }

        public static void Update(GameTime gameTime)
        {
            mTimer = gameTime.ElapsedGameTime.Milliseconds;
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    mButtonHolder[i, j] -= mTimer;
                }
            }
        }

        #region Joystick Methods

        //PlayerIndex? quiere decir que es nuleable.
        public static bool isButtonPressed(Buttons button,PlayerIndex? controllingPlayer,
            out PlayerIndex playerIndex)
        {
            if (controllingPlayer.HasValue)
            {
                playerIndex = controllingPlayer.Value;
                int i = (int)playerIndex;
                return (currentGamePadState[i].IsButtonDown(button));
            }
            else
            {
                return (isButtonPressed(button, PlayerIndex.One, out playerIndex) ||
                    isButtonPressed(button, PlayerIndex.Two, out playerIndex) ||
                    isButtonPressed(button, PlayerIndex.Three, out playerIndex) ||
                    isButtonPressed(button, PlayerIndex.Four, out playerIndex));
            }
        }
        public static bool IsNewButtonPress(Buttons button, PlayerIndex? controllingPlayer,
            out PlayerIndex playerIndex)
        {
            if (controllingPlayer.HasValue)
            {
                playerIndex = controllingPlayer.Value;
                int i = (int)playerIndex;
                return (!oldGamePadState[i].IsButtonDown(button) && currentGamePadState[i].IsButtonDown(button));
            }
            else
            {
                return (IsNewButtonPress(button, PlayerIndex.One, out playerIndex) ||
                    IsNewButtonPress(button, PlayerIndex.Two, out playerIndex) ||
                    IsNewButtonPress(button, PlayerIndex.Three, out playerIndex) ||
                    IsNewButtonPress(button, PlayerIndex.Four, out playerIndex));
            }
        }

        public static bool isRepeatingButton(Buttons button, PlayerIndex controllingPlayer)
        {
            PlayerIndex index;
            if (IsNewButtonPress(button, controllingPlayer, out index))
            {
                SetButtonHolder(button, controllingPlayer,mRelease);
                return true;
            }
            
            bool a = isButtonPressed(button, controllingPlayer, out index);
            bool b = AskButtonHolder(button, controllingPlayer);
            if (isButtonPressed(button, controllingPlayer, out index) && AskButtonHolder(button, controllingPlayer))
            {
                SetButtonHolder(button, controllingPlayer, mDelay);
                return true;
            }
            return false;
        }
        static void SetButtonHolder(Buttons button, PlayerIndex index, int carga)
        {
            switch (button)
            {
                case Buttons.A:
                    mButtonHolder[(int)index, 0] = carga;
                    break;
                case Buttons.B:
                    mButtonHolder[(int)index, 1] = carga;
                    break;
                case Buttons.X:
                    mButtonHolder[(int)index, 2] = carga;
                    break;
                case Buttons.Y:
                    mButtonHolder[(int)index, 3] = carga;
                    break;
            }
        }
        static bool AskButtonHolder(Buttons button, PlayerIndex index)
        {
            switch (button)
            {
                case Buttons.A:
                    return (mButtonHolder[(int)index, 0] <= 0);
                case Buttons.B:
                    return (mButtonHolder[(int)index, 1] <= 0);
                case Buttons.X:
                    return (mButtonHolder[(int)index, 2] <= 0);
                case Buttons.Y:
                    return (mButtonHolder[(int)index, 3] <= 0);
                default:
                    return false;
            }
        }

#endregion

        #region Keyboard Methods

        public static bool isKeyPressed(Keys key)
        {
            if (currentKeyboardState.IsKeyDown(key))
                return true;
            else
                return false;
        }
        public static bool IsNewKeyPress(Keys key)
        {

            if (!oldKeyboardState.IsKeyDown(key) && currentKeyboardState.IsKeyDown(key))
                return true;
            else
                return false;
        }

        #endregion

        #region Mouse Methods

        public static bool leftClickPressed()
        {
            if (currentMouseState.LeftButton == ButtonState.Pressed)
                return true;
            else
                return false;
        }
        public static bool rightClickPressed()
        {
            if (currentMouseState.RightButton == ButtonState.Pressed)
                return true;
            else
                return false;
        }
        public static bool newLeftClick()
        {
            if (oldMouseState.LeftButton != ButtonState.Pressed && 
                currentMouseState.LeftButton == ButtonState.Pressed)
                return true;
            else
                return false;
            
        }
        public static bool newRightClick()
        {
            if (oldMouseState.RightButton != ButtonState.Pressed &&
                currentMouseState.RightButton == ButtonState.Pressed)
                return true;
            else
                return false;
        }


        public static MouseState CurrentMouseState
        {
            get { return currentMouseState; }
        }
        #endregion



        /// <summary>
        /// Checks for a "menu select" input action.
        /// The controllingPlayer parameter specifies which player to read input for.
        /// If this is null, it will accept input from any player. When the action
        /// is detected, the output playerIndex reports which player pressed it.
        /// </summary>
        static public bool IsMenuSelect(PlayerIndex? controllingPlayer,
                                 out PlayerIndex playerIndex)
        {
            return (IsNewButtonPress(Buttons.A, controllingPlayer, out playerIndex) ||
                    IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex));
        }


        /// <summary>
        /// Checks for a "menu cancel" input action.
        /// The controllingPlayer parameter specifies which player to read input for.
        /// If this is null, it will accept input from any player. When the action
        /// is detected, the output playerIndex reports which player pressed it.
        /// </summary>
        static public bool IsMenuCancel(PlayerIndex? controllingPlayer,
                                 out PlayerIndex playerIndex)
        {
            return (IsNewButtonPress(Buttons.B, controllingPlayer, out playerIndex) ||
                    IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex));
        }


        /// <summary>
        /// Checks for a "menu up" input action.
        /// The controllingPlayer parameter specifies which player to read
        /// input for. If this is null, it will accept input from any player.
        /// </summary>
        static public bool IsMenuUp(PlayerIndex? controllingPlayer)
        {
            PlayerIndex playerIndex;

            return (IsNewButtonPress(Buttons.DPadUp, controllingPlayer, out playerIndex) ||
                    IsNewButtonPress(Buttons.LeftThumbstickUp, controllingPlayer, out playerIndex));
        }


        /// <summary>
        /// Checks for a "menu down" input action.
        /// The controllingPlayer parameter specifies which player to read
        /// input for. If this is null, it will accept input from any player.
        /// </summary>
        static public bool IsMenuDown(PlayerIndex? controllingPlayer)
        {
            PlayerIndex playerIndex;

            return (IsNewButtonPress(Buttons.DPadDown, controllingPlayer, out playerIndex) ||
                    IsNewButtonPress(Buttons.LeftThumbstickDown, controllingPlayer, out playerIndex));
        }


        /// <summary>
        /// Checks for a "pause the game" input action.
        /// The controllingPlayer parameter specifies which player to read
        /// input for. If this is null, it will accept input from any player.
        /// </summary>
        static public bool IsPauseGame(PlayerIndex? controllingPlayer)
        {
            PlayerIndex playerIndex;

            return (IsNewButtonPress(Buttons.Back, controllingPlayer, out playerIndex) ||
                    IsNewButtonPress(Buttons.Start, controllingPlayer, out playerIndex));
        }
    }
}
